package net.huashitong.service.user;

import com.yunpian.sdk.model.SmsSingleSend;
import net.huashitong.config.ProjectConfig;
import net.huashitong.service.money.SsMoneyGoldService;
import net.huashitong.ssydt.exceptions.ServiceException;
import net.huashitong.ssydt.money.entity.SsMoneyGold;
import net.huashitong.ssydt.security.entity.SsUserLoginToken;
import net.huashitong.ssydt.security.utils.MobileUtils;
import net.huashitong.ssydt.security.utils.UUIDGenerator;
import net.huashitong.ssydt.user.entity.SsUserValid;
import net.huashitong.ssydt.user.entity.vo.*;
import net.huashitong.ssydt.user.util.VerificationCodeUtils;
import net.huashitong.user.UserManager;
import net.huashitong.user.http.Result;
import net.huashitong.user.results.User;
import net.huashitong.user.results.User3PartyToken;
import net.huashitong.user.results.UserPlain;
import net.huashitong.user.vo.ThirdLoginVO;
import net.huashitong.user.vo.ThirdRegisterInVO;
import net.huashitong.user.vo.UserLoginVO;
import net.huashitong.user.vo.UserRegisterInVO;
import net.huashitong.yunpian.YunpianService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @author shaoxian.zhong
 * @create 2018-06-25 17:57
 */
@Transactional
@Service
public class WebUserServiceImpl implements UserService {
    private Logger logger = LoggerFactory.getLogger(WebUserServiceImpl.class);

    @Autowired
    private UserManager userManager;
    @Autowired
    private YunpianService yunpianService;

    @Autowired
    private SsUserValidService ssUserValidService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private SsUserLoginTokenService ssUserLoginTokenService;

    @Autowired
    private SsMoneyGoldService ssMoneyGoldService;

    @Override
    public String getByThirdAccountWithToken(String thirdAccount, String token) {
        Result<String> rs = userManager.getUserIdByThirdAccountWithToken(thirdAccount, token);
        return getResults(rs);
    }

    @Override
    public void thirdRegister(ThirdRegisterInVO thirdRegisterInVO) {
        thirdRegisterInVO.setProductSource(ProjectConfig.PRODUCT_CODE);
        Result rs = userManager.thirdRegister(thirdRegisterInVO);
        getResults(rs);
    }

    @Override
    public void smsMy(String userId) {
        Result<User> result = userManager.get(userId);
        getResultHandler(result);
        String mobile = result.getResults().getMobile();
        if (StringUtils.isBlank(mobile)) {
            throw new ServiceException("请绑定手机");
        }
        SmsVo smsVo = new SmsVo();
        smsVo.setMobile(mobile);
        this.sms(smsVo, false);
    }

    @Override
    public void sms(SmsVo smsVo, boolean verification) {
        if (verification) {
            verificationCode(smsVo);
        }
        SsUserValid ssUserValid = this.produceVaildCode(smsVo.getMobile());
        com.yunpian.sdk.model.Result<SmsSingleSend> rs = yunpianService.sendSmS(ssUserValid);
        if (rs.getCode() != 0) {
            logger.error("验证码发送失败,code={},msg={},Throwable={}", rs.getCode(), rs.getMsg(), rs.getThrowable());
            String msg = String.format("验证码发送失败,code=%d", rs.getCode());
            throw new ServiceException(msg);
        }
    }

    /**
     * 验证码调用合法性校验
     *
     * @param smsVo
     */
    private void verificationCode(SmsVo smsVo) {
        boolean isToken = VerificationCodeUtils.verificationToken(smsVo.getMobile(), smsVo.getToken(), smsVo.getRandomStr());
        if (!isToken) {
            throw new ServiceException("非法操作");
        }
        boolean isSign = VerificationCodeUtils.verificationSign(smsVo.getMobile(), smsVo.getToken(), smsVo.getTimestamp(), smsVo.getSign());
        if (!isSign) {
            throw new ServiceException("非法操作");
        }
    }

    /**
     * 返回结果处理程序
     *
     * @param result
     */
    private void getResultHandler(Result result) {
        if (!Result.Status.SUCCESS.equals(result.getCode())) {
            throw new ServiceException(result.getCode(), result.getMessage());
        }
    }

    /**
     * 生产验证码
     *
     * @param mobile
     * @return
     */
    private SsUserValid produceVaildCode(String mobile) {
        char[] codeSeq = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
        Random random = new Random();
        StringBuilder code = new StringBuilder();

        String randomCode;
        for (int i = 0; i < 6; i++) {
            randomCode = String.valueOf(codeSeq[random.nextInt(codeSeq.length)]);
            code.append(randomCode);
        }
        SsUserValid ssUserValid = new SsUserValid();
        ssUserValid.setMoblie(mobile);
        ssUserValid.setVaildCode(code.toString());
        ssUserValid.setSendCurrentTimeMillis(System.currentTimeMillis());
        ssUserValid.setIsEnabled(0);
        ssUserValidService.save(ssUserValid);
        return ssUserValid;
    }

    @Override
    public void passwordMy(String userId, PasswordMyVO passwordMyVO) {
        Result<User> result = userManager.get(userId);
        getResultHandler(result);
        String mobile = result.getResults().getMobile();
        if (StringUtils.isBlank(mobile)) {
            throw new ServiceException("请绑定手机");
        }
        PasswordVO passwordVO = new PasswordVO();
        passwordVO.setMobile(mobile);
        passwordVO.setPassword(passwordMyVO.getPassword());
//        passwordVO.setVaildCode(passwordMyVO.getVaildCode());
        password(passwordVO);
    }

    @Override
    public void password(PasswordVO passwordVO) {
        //校验验证码
        if (ssUserValidService.isPast5MinOrErr(passwordVO.getMobile(), passwordVO.getVaildCode())) {
            throw new ServiceException("验证码错误");
        }
        net.huashitong.user.vo.PasswordVO passwordVO1 = new net.huashitong.user.vo.PasswordVO();
        passwordVO1.setMobile(passwordVO.getMobile());
        passwordVO1.setPassword(passwordVO.getPassword());
        Result<String> result = userManager.updatePassword(passwordVO1);
        getResultHandler(result);
    }

    @Override
    public UserPlain thirdLogin(ThirdLoginVO thirdLoginVO) {
        thirdLoginVO.setProductSource(ProjectConfig.PRODUCT_CODE);
        Result<UserPlain> rs = userManager.thirdLogin(thirdLoginVO);
        UserPlain userPlain = getResults(rs);

        //第一次登录创建金币账户
        saveMoneyGold(userPlain.getUserId());

        //写入token
        ssUserLoginTokenService.login(userPlain.getUserId());

        return userPlain;
    }

    @Override
    public LoginOutVO login(UserLoginVO userLoginVO) {
        String keys = String.format("user:password:%s", userLoginVO.getMobile());
        String number = stringRedisTemplate.opsForValue().get(keys);
        if (number == null) {
            stringRedisTemplate.opsForValue().set(keys, "1", 10, TimeUnit.MINUTES);
        } else {
            BoundValueOperations<String, String> boundValueOperations = stringRedisTemplate.boundValueOps(keys);
            boundValueOperations.increment(1);
            boundValueOperations.expire(10, TimeUnit.MINUTES);
            if (Integer.parseInt(number) >= 5) {
                throw new ServiceException("有人尝试登录您的帐号超过五次, 系统自动开启了保护模式, 请十分钟后再试");
            }
        }
//        UserLoginVO userLoginVO = new UserLoginVO();
//        userLoginVO.setMobile(loginInVO.getMobile());
//        userLoginVO.setPassword(loginInVO.getPassword());
//        userLoginVO.setTerminal(loginInVO.getTerminal());
//        userLoginVO.setProductSource(SsydtConsts.PRODUCT_CODE);
//        userLoginVO.setIp(WebUtils.getClientIpAddr(request));
//        userLoginVO.setDeviceCode(loginInVO.getDeviceCode());
//        userLoginVO.setDeviceType(loginInVO.getDeviceType());
//        userLoginVO.setDeviceOperation(loginInVO.getDeviceOperation());
//        userLoginVO.setClientVersion(loginInVO.getClientVersion());
//        userLoginVO.setUserAgent(UserUtils.getUserSession().get().getUserAgent());
        Result<UserPlain> result = userManager.login(userLoginVO);
        //错误次数拦截

        getResultHandler(result);

        stringRedisTemplate.delete(keys);
        String userId = result.getResults().getUserId();
        //写入token
        SsUserLoginToken ssUserLoginToken = ssUserLoginTokenService.login(userId);
        return getLoginInfo(userId, ssUserLoginToken);
    }

    /**
     * 登录后统一返回信息
     *
     * @param userId
     * @param ssUserLoginToken
     * @return
     */
    private LoginOutVO getLoginInfo(String userId, SsUserLoginToken ssUserLoginToken) {

        //第一次登录创建金币账户
        saveMoneyGold(userId);

        LoginOutVO loginOutVO = new LoginOutVO();
        loginOutVO.setUserId(userId);
//        loginOutVO.setToken(Base64Utils.encode(ssUserLoginToken.getToken().getBytes()));
        loginOutVO.setExpiration(ssUserLoginToken.getExpiration());
        return loginOutVO;
    }

    private void saveMoneyGold(String userId) {
        SsMoneyGold ssMoneyGold = ssMoneyGoldService.getByUserId(userId);
        if (ssMoneyGold == null) {
            ssMoneyGold = new SsMoneyGold();
            ssMoneyGold.setUserId(userId);
            ssMoneyGold.setGoldNumber(0L);
            ssMoneyGoldService.save(ssMoneyGold);
        }
    }

    @Override
    public UserOutVO getByUserId(String userId) {
        Result<User> result = userManager.get(userId);
        if (!Result.Status.SUCCESS.equals(result.getCode())) {
            throw new ServiceException(result.getMessage());
        }
        User user = result.getResults();
        UserOutVO userOut = new UserOutVO();
        BeanUtils.copyProperties(user, userOut);
        userOut.setMobile(MobileUtils.getEncodeMobile(userOut.getMobile()));

        String imageUrl = userOut.getImageUrl();
        if (StringUtils.isNotBlank(imageUrl) && imageUrl.startsWith("2")) {
            imageUrl = " http://img.huashitong.net/api/sys/picture/downloadBigPic/" + imageUrl;
            userOut.setImageUrl(imageUrl);
        }
        return userOut;
    }

    @Override
    public IsRegisterVO mobileIsRegister(String mobile) {
        Result<Boolean> rs = userManager.mobileIsRegiter(mobile);
        getResultHandler(rs);
        String randomStr = UUIDGenerator.uuid2();
        IsRegisterVO vo = new IsRegisterVO();
        vo.setRegister(rs.getResults());
        vo.setToken(VerificationCodeUtils.getToken(mobile, randomStr));
        vo.setRandomStr(randomStr);
        return vo;
    }

    @Override
    public void register(RegisterVO registerVO) {
        //校验验证码
        if (ssUserValidService.isPast5MinOrErr(registerVO.getMobile(), registerVO.getVaildCode())) {
            throw new ServiceException("验证码错误");
        }
        //执行注册
        UserRegisterInVO userRegisterInVO = registerVO.getUserRegisterInVO(registerVO);
        Result<String> result = userManager.regiter(userRegisterInVO);
        getResultHandler(result);

    }

    @Override
    public User get(String userId) {
        Result<User> rs = userManager.get(userId);
        return getResults(rs);
    }

    @Override
    public List<User3PartyToken> listBindings(String userId) {
        return userManager.listBindings(userId).getResults();
    }

    private <T extends Serializable> T getResults(Result<T> result) {
        if (result.getCode().equals(Result.Status.SUCCESS)) {
            return result.getResults();
        } else {
            throw new ServiceException(result.getCode(), result.getMessage());
        }
    }
}
